import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

public class ShawnWroteThis implements AI {
	public Action decide(Battle game_state){
		return null;
	}
	
	private static boolean is_a_healer(Combatant c){
		if(c.wlvl(WType.STAFF).is_at_least(WLvl.E)){
			return true;
		}
		return false;
	}
	
	private static Collection<Action> get_all_attack_actions(Battle game_state){
		Collection<Action> result = new LinkedList<Action>();
		Set<Combatant> redTeam = game_state.roster(Team.RED);
		for(Combatant curr: redTeam){
			if(game_state.hasnt_moved(curr) && !is_a_healer(curr)){
				Map<MapLocation,Path> move_range = game_state.move_range(curr);
				for(MapLocation destination: move_range.keySet()) {
				      if(game_state.at(destination) != null && !game_state.at(destination).equals(curr))
				          continue;
				      Battle temp_context = game_state.clone();
				      temp_context.move(curr,destination);
				      for(Combatant target: temp_context) {
				          if(curr.can_attack(temp_context,target)){
				        	  result.add(Action.attack(curr,destination,target));
				          }
				      }
				}
			}
		}
		return result;
	}
	
	public static class Ally_Below_Half_And_Healer_Available extends DecisionTree.Decision{
		private Battle game_state;
		public Ally_Below_Half_And_Healer_Available(DecisionTree.Node yes_branch, DecisionTree.Node no_branch, Battle game_state){
			super(yes_branch, no_branch);
			this.game_state = game_state;
		}
		
		public boolean decide(){
			boolean ally_below_half = false;
			boolean decision = false;
			Set<Combatant> redTeam = game_state.roster(Team.RED);
			
			for(Combatant ally: redTeam){
				if(ally.hp()/ally.max_hp() < 50 && !is_a_healer(ally)){
					ally_below_half = true;
					break;
				}
			}
			
			for(Combatant curr: redTeam){
				if (is_a_healer(curr)){
					if (game_state.hasnt_moved(curr)){
						if(ally_below_half){
							decision = true;
						}
					}
				}
			}
			return decision;
		}
	}
	
	public static class No_Ally_Attackers_Remaining extends DecisionTree.Decision{
		private Battle game_state;
		public No_Ally_Attackers_Remaining (DecisionTree.Node yes_branch, DecisionTree.Node no_branch, Battle game_state){
			super(yes_branch, no_branch);
			this.game_state = game_state;
		}
		
		public boolean decide(){
			Set<Combatant> redTeam = game_state.roster(Team.RED);
			boolean decision = false;
			for(Combatant ally: redTeam){
				if(game_state.hasnt_moved(ally) && !is_a_healer(ally)){
					decision = true;
				}
			}
			return decision;
		}
	}
	
	public static class Enemy_In_Attack_Range extends DecisionTree.Decision{
		private Battle game_state;
		public Enemy_In_Attack_Range (DecisionTree.Node yes_branch, DecisionTree.Node no_branch, Battle game_state){
			super(yes_branch, no_branch);
			this.game_state = game_state;
		}
		
		public boolean decide(){
			boolean decision = false;
			Set<Combatant> redTeam = game_state.roster(Team.RED);
			for(Combatant curr: redTeam){
				if(game_state.hasnt_moved(curr) && !is_a_healer(curr)){
					Map<MapLocation,Path> move_range = game_state.move_range(curr);
					for(MapLocation destination: move_range.keySet()) {
					      if(game_state.at(destination) != null && !game_state.at(destination).equals(curr))
					          continue;
					      Battle temp_context = game_state.clone();
					      temp_context.move(curr,destination);
					      for(Combatant target: temp_context) {
					          if(curr.can_attack(temp_context,target)){
					              decision = true;
					              break;
					          }
					      }
					}
				}
			}
			return decision;
		}
	}
	
	public static class Is_There_A_Good_Target extends DecisionTree.Decision{
		private Battle game_state;
		public Is_There_A_Good_Target (DecisionTree.Node yes_branch, DecisionTree.Node no_branch, Battle game_state){
			super(yes_branch, no_branch);
			this.game_state = game_state;
		}
		
		public boolean decide(){
			double MINIMUM = 0.0;
			Collection<Action> result = get_all_attack_actions(game_state);
			for(Action A: result) if (A.calc_value(game_state) > MINIMUM) return true;
			return false;
		}
	}
	
	class Heal_Weakest_Ally_Move_To_Least_Threatened extends DecisionTree.Actuator{
		private Battle game_state;
		
		public Heal_Weakest_Ally_Move_To_Least_Threatened(Battle game_state){
			this.game_state = game_state;
		}
		
		public Action perform() {
			Set<Combatant> redTeam = game_state.roster(Team.RED);
			Combatant healer = null;
			Combatant weakest_ally = null;
			MapLocation weakest_ally_loc = null;
			int most_health_missing = 0;
			Action result = null;
			for(Combatant curr: redTeam){
				if(is_a_healer(curr) && game_state.hasnt_moved(curr)){
					healer = curr;
				}
			}
			
			for(Combatant curr: redTeam){
				if((curr.max_hp() - curr.hp()) > most_health_missing && !healer.equals(curr)){
					Map<MapLocation,Path> move_range = game_state.move_range(curr);
					for(MapLocation destination: move_range.keySet()) {
					      if(game_state.at(destination) != null && !game_state.at(destination).equals(curr))
					          continue;
					      Battle temp_context = game_state.clone();
					      temp_context.move(healer,destination);
				          if(healer.can_use_staff(temp_context,curr)){
				        	  if (weakest_ally_loc == null || temp_context.location_isnt_threatened(destination, Team.RED)){
				        		  weakest_ally = curr;
						       	  most_health_missing = (curr.max_hp() - curr.hp());
						       	  weakest_ally_loc = destination;
				        	  }
					      }
					}
				}
			}
			
			if(healer != null && weakest_ally != null){
				MapLocation best_loc_near_weakest_ally;
				result = Action.staff(healer, best_loc_near_weakest_ally, weakest_ally);
			}
			return result;
		}
	}
	
	class Heal_Weakest_Ally_Without_Threatening_Self extends DecisionTree.Actuator{
		private Battle game_state;
		
		public Heal_Weakest_Ally_Without_Threatening_Self(Battle game_state){
			this.game_state = game_state;
		}
		
		public Action perform(){
			Action result = null;
			
			// NEEDS CODE
			Map<MapLocation, Path> safe_range = null; // this is a list of locations that are not threatened and in range
			// NEEDS CODE 
			
			Set<Combatant> redTeam = game_state.roster(Team.RED);
			Combatant healer = null;
			Combatant weakest_ally = null;
			int most_health_missing = 0;
			MapLocation weakest_ally_loc = null;
			
			for(Combatant curr: redTeam){
				if(is_a_healer(curr) && game_state.hasnt_moved(curr)){
					healer = curr;
				}
			}
			
			for(Combatant curr: redTeam){
				if((curr.max_hp() - curr.hp()) > most_health_missing && !healer.equals(curr)){
					for(MapLocation destination: safe_range.keySet()) {
					      if(game_state.at(destination) != null && !game_state.at(destination).equals(curr))
					          continue;
					      Battle temp_context = game_state.clone();
					      temp_context.move(curr,destination);
				          if(healer.can_use_staff(temp_context,curr)){
					       	  weakest_ally = curr;
					       	  most_health_missing = (curr.max_hp() - curr.hp());
					       	  weakest_ally_loc = destination;
					      }
					}
				}
			}
			
			if(healer != null && weakest_ally != null){
				result = Action.staff(healer, weakest_ally_loc, weakest_ally);
			}
			// NEEDS WORK!!!!
			//else result = Action.wait(healer, )
			return result;
		}
	}

	class Run_Away extends DecisionTree.Actuator {
		private Battle game_state;

		public Run_Away(Battle gs) {
			game_state = gs;
		}

		public Action perform() {
			return null;
		}
	}
	/*
	public Set<MapLocation> getHorizon() {
		Set<MapLocation> result = new Set<MapLocation>();
		
	}
	*/
}